<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>日历</title>
    <style>
      .container {
        background-color: #fff;
        width: 985px;
        margin: 16px auto;
        border: 1px solid #f0f0f0;
        border-radius: 2px;
        padding: 42px 24px;
      }

      .content {
        color: #000000d9;
        font-size: 14px;
      }

      .select {
        display: flex;
        justify-content: flex-end;
        padding: 12px 0;
      }

      /* 年份下拉框样式 */
      #year {
        background-color: #fff;
        border: 1px solid #d9d9d9;
        height: 30px;
        box-sizing: border-box;
        border-radius: 2px;
        cursor: pointer;
        padding: 0 29px 0 11px;
        outline: none;
        /*隐藏select的下拉图标*/
        appearance: none;
        transition: color 0.3s, background 0.3s, border-color 0.3s;
      }

      #year:hover {
        border-color: #1890ff;
      }

      .select_year {
        position: relative;
      }

      .select_year::after {
        content: "";
        display: inline-block;
        width: 18px;
        height: 30px;
        background: url(./img/select.svg) no-repeat left;
        background-size: 18px;
        /*通过定位将图标放在合适的位置*/
        position: absolute;
        right: 6px;
        top: 0;
        /*给自定义的图标实现点击下来功能 清除鼠标事件*/
        pointer-events: none;
      }

      /* 月份下拉框样式 */
      #month {
        background-color: #fff;
        border: 1px solid #d9d9d9;
        height: 30px;
        box-sizing: border-box;
        border-radius: 2px;
        cursor: pointer;
        padding: 0 29px 0 11px;
        outline: none;
        margin-left: 8px;
        /*隐藏select的下拉图标*/
        appearance: none;
        transition: color 0.3s, background 0.3s, border-color 0.3s;
      }

      #month:hover {
        border-color: #1890ff;
      }

      .select_month {
        position: relative;
      }

      .select_month::after {
        content: "";
        display: inline-block;
        width: 18px;
        height: 30px;
        background: url(./img/select.svg) no-repeat left;
        background-size: 18px;
        /*通过定位将图标放在合适的位置*/
        position: absolute;
        right: 6px;
        top: 0;
        /*给自定义的图标实现点击下来功能 清除鼠标事件*/
        pointer-events: none;
      }

      /* 月份按钮样式 */
      #btn_month {
        margin-left: 8px;
        background-color: #fff;
        border: 1px solid #d9d9d9;
        height: 30px;
        line-height: 30px;
        box-sizing: border-box;
        border-radius: 2px;
        padding: 0 15px;
        cursor: pointer;
      }

      #btn_month:hover {
        color: #1890ff;
      }

      #btn_month.btn_active {
        color: #1890ff;
        border-color: #1890ff;
      }

      /*  */
      #btn_year {
        background-color: #fff;
        border: 1px solid #d9d9d9;
        height: 30px;
        line-height: 30px;
        box-sizing: border-box;
        border-radius: 2px;
        padding: 0 15px;
        cursor: pointer;
      }

      #btn_year:hover {
        color: #1890ff;
      }

      #btn_year.btn_active {
        color: #1890ff;
        border-color: #1890ff;
      }

      /* 日历展示区 */
      .date {
        display: block;
        width: 100%;
        text-align: right;
        background: #fff;
        display: flex;
        flex-direction: column;
      }

      /* 月份日历 */
      .date .data_month {
        padding: 8px 0;
      }

      .date_month table {
        width: 100%;
      }

      .date_month table thead {
        box-sizing: border-box;
      }

      .date_month table thead th {
        padding: 0 12px 5px 0;
        line-height: 18px;
        width: 36px;
        color: #000000d9;
        font-weight: 400;
      }

      .date_month table tbody {
        box-sizing: border-box;
      }

      .date_month table tbody td {
        font-weight: 400;
        height: 116px;
        margin: 0 4px;
        padding: 4px 14px 0;
        vertical-align: top;
        border-top: 2px solid #f0f0f0;
        transition: all 0.3s;
        color: #000000d9;
      }

      .date_month table tbody td:hover {
        background: #f5f5f5;
      }

      .date_month table tbody td.notBelong {
        color: #00000040;
      }

      .date_month table tbody td.click {
        background: #e6f7ff;
        color: #1890ff;
      }

      .date_month table tbody td.active {
        border-color: #1890ff;
      }

      /* 年份月历 */
      .date .data_year {
        padding: 8px 0;
      }

      .date_year table {
        width: 100%;
      }

      .date_year table tbody {
        box-sizing: border-box;
      }

      .date_year table tbody td {
        font-weight: 400;
        height: 116px;
        margin: 0 4px;
        padding: 4px 14px 0;
        vertical-align: top;
        border-top: 2px solid #f0f0f0;
        transition: all 0.3s;
        color: #000000d9;
      }

      .date_year table tbody td:hover {
        background: #f5f5f5;
      }

      .date_year table tbody td.notBelong {
        color: #00000040;
      }

      .date_year table tbody td.click {
        background: #e6f7ff;
        color: #1890ff;
      }

      .date_year table tbody td.active {
        border-color: #1890ff;
      }
    </style>
  </head>

  <body>
    <div class="container">
      <!-- 外层容器--外壳 -->
      <div class="content">
        <!--内部容器--包裹内容 -->
        <div class="select">
          <!-- 年月选择区 -->
          <div class="select_year"><select id="year"></select></div>
          <div class="select_month"><select id="month"></select></div>
          <button id="btn_month" class="btn_active">月</button>
          <button id="btn_year">年</button>
        </div>
        <div class="date">
          <!-- 日历展示区 -->

          <div class="date_month">
            <!-- 月份日历 -->
            <table cellspacing="10">
              <thead>
                <tr>
                  <th>一</th>
                  <th>二</th>
                  <th>三</th>
                  <th>四</th>
                  <th>五</th>
                  <th>六</th>
                  <th>日</th>
                </tr>
              </thead>
              <tbody></tbody>
            </table>
          </div>
          <div class="date_year">
            <!-- 年份日历 -->
            <table cellspacing="10">
              <tbody>
                <tr>
                  <td>1月</td>
                  <td>2月</td>
                  <td>3月</td>
                </tr>
                <tr>
                  <td>4月</td>
                  <td>5月</td>
                  <td>6月</td>
                </tr>
                <tr>
                  <td>7月</td>
                  <td>8月</td>
                  <td>9月</td>
                </tr>
                <tr>
                  <td>10月</td>
                  <td>11月</td>
                  <td>12月</td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>
      </div>
    </div>
    <!-- 引入day.js -->
    <script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.4.1/dayjs.min.js"></script>
    <script>
      window.onload = function () {
        let select_year = document.getElementById("year"); //获取年份下拉列表
        let select_month = document.getElementById("month"); //获取月份下拉列表
        //年份选择区间 支持日期范围为：2015年~2025年
        for (let i = 2015; i <= 2025; i++) {
          //循环遍历设置年份
          let node = document.createElement("option"); //创建可用选项节点
          node.setAttribute("value", i); //设置可用选项的value值为年份值
          node.innerHTML = `${i}年`; //设置可用选项的年份
          select_year.appendChild(node); //追加可用选项节点
        }
        //月份选择区间 支持日期范围为：1月~12月
        for (let i = 1; i <= 12; i++) {
          //循环遍历设置年份
          let node = document.createElement("option"); //创建可用选项节点
          node.setAttribute("value", i); //设置可用选项的value值为月份值
          node.innerHTML = `${i}月`; //设置可用选项的月份
          select_month.appendChild(node); //追加可用选项节点
        }
        // 获取日期函数--当前月份有多少天
        function getDates(year, month) {
          //需要传入年 和 月
          let date = new Date(year, month, 0);
          return date.getDate(); //调用获取日期函数即可获取当前月份有多少天,然后返回
        }

        //获取当月份第一天是星期几函数
        function getWeek(year, month) {
          //需要传入年 和 月
          let date = new Date(year, month - 1, 0);
          return date.getDay() + 1; //返回值是 0（周日） 到 6（周六） 之间的一个整数 需要+1
        }

        // 获取当前年月日
        let now = dayjs();
        let now_year = now.year(); //获取当前年份
        let now_month = now.month() + 1; //获取当前月份 month()获取的值是0-11 所以当前月份需要加1
        //设置年份选择和月份选择的默认值
        select_year.value = now_year;
        select_month.value = now_month;

        // let now_date = now.date(); //获取当前日期  dayjs 的 date()使用报错
        let now_date = getDates(now_year, now_month); //获取当前日期--当前月份有多少天
        // let now_day = now.day(); //dayjs 的 day()使用报错

        // 月份日历显示
        let month_tbody = document.querySelector(".date_month tbody");
        // 传入年 月 当月天数 显示日历
        function showMonth(year, month, days) {
          month_tbody.innerHTML = ""; //显示日历前先清空日历
          // 月份日历 tbody 结构7行6列
          // 日历为固定7行
          for (let i = 1; i < 7; i++) {
            let node = document.createElement("tr");
            month_tbody.appendChild(node);
          }
          // 本月第一天星期几
          let first_day_week = getWeek(year, month);
          // 获取上个月有多少天
          let last_month_days = getDates(year, month - 1);
          // 显示本月第一天所在周的前几天 并添加 .notBelong 样式
          let first_row_tr = month_tbody.querySelectorAll("tr")[0]; //获取日历第一行
          for (let i = 1; i < first_day_week; i++) {
            // 获取日期
            let day = last_month_days - first_day_week + 1 + i;
            let node = document.createElement("td");
            node.className = "notBelong";
            node.innerHTML = day;
            first_row_tr.appendChild(node);
          }
          // 显示本月日期
          for (let i = 1; i <= days; i++) {
            let this_row = parseInt((i + first_day_week - 2) / 7); //当前 日期 i 是第几行
            // console.log(this_row, i);
            let node = document.createElement("td");
            node.innerHTML = i;
            month_tbody.querySelectorAll("tr")[this_row].appendChild(node);
          }
          // 显示本月最后一天所在周的后几天 并添加 .notBelong 样式
          for (let i = days + first_day_week - 1; i < 6 * 7; i++) {
            let this_row = parseInt(i / 7); //当前 日期 是第几行
            let day = i - days - first_day_week + 2; //当前是下个月的第几天
            // console.log(this_row, day);
            let node = document.createElement("td");
            node.className = "notBelong";
            node.innerHTML = day;
            month_tbody.querySelectorAll("tr")[this_row].appendChild(node);
          }
          // 为当前日期 td 和当前月 td 添加
          if (year == now_year && month == now_month) {
            //年为当前年，月为当前月
            let year_tbody = document.querySelector(".date_year tbody");
            let all_year_tds = year_tbody.querySelectorAll("td");
            all_year_tds.forEach((item) => {
              if (item.innerHTML == `${month}月`) {
                //判断是否为当前月
                item.className = "active";
              }
            });
            let day = new Date().getDate(); //获取当前日期
            let month_tbody = document.querySelector(".date_month tbody");
            let all_month_tds = month_tbody.querySelectorAll("td");
            all_month_tds.forEach((item) => {
              if (item.innerHTML == day) {
                //判断是否为当前日期
                item.className = "active";
              }
            });
          }
        }
        // 默认显示当前日期
        showMonth(now_year, now_month, now_date);
        // 监听月份tbody的点击事件,当点击td时为当前点击的td添加 .click 类
        month_tbody.addEventListener("click", (e) => {
          let all_month_tds = month_tbody.querySelectorAll("td");
          let year = select_year.value;
          let month = select_month.value;
          all_month_tds.forEach((item) => {
            //年为当前年，月为当前月
            if (item.className == "notBelong") {
              //.notBelong 类 的td 则不清除样式
              item.className = "notBelong";
            }
            if (
              item.className == "active" ||
              item.className == "active click"
            ) {
              //.active 类 的td 则不清除 .activ 样式
              if (year == now_year && month == now_month) {
                item.className = "active";
              }
            }
            if (item.className == "click") {
              //清除之前添加的click
              item.className = "";
            }
          });
          if (e.target.className == "notBelong") {
            //如果点击的是  .notBelong 样式 的td 则会跳转到上个月 或 下个月
            let year = select_year.value;
            let month = select_month.value;
            if (e.target.innerHTML > (6 * 7) / 2) {
              //.notBelong 样式 的td的日期 当前大于单元数的一半 表示是要跳转到上个月
              if (month == 1) {
                //如果当前是第一个月，则年数减1，月数置为12
                year--;
                month = 12;
                if (year < 2015) {
                  //不超过2015年1月
                  year = 2015;
                  month = 1;
                }
              } else {
                //否则月数减1
                month--;
              }
              // 更新 年 月
              select_year.value = year;
              select_month.value = month;
              let date = getDates(year, month);
              // 传入年 月 当月天数
              showMonth(year, month, date);
            }
            if (e.target.innerHTML < (6 * 7) / 2) {
              //.notBelong 样式 的td的日期 当前小于单元数的一半 表示是要跳转到下个月
              if (month == 12) {
                //如果当前是最后一个月，则年数加1，月数置为1
                year++;
                month = 1;
                if (year > 2025) {
                  //不超过2025年12月
                  year = 2025;
                  month = 12;
                }
              } else {
                //否则月数加1
                month++;
              }
              select_year.value = year;
              select_month.value = month;

              let date = getDates(year, month);
              // 传入年 月 当月天数
              showMonth(year, month, date);
            }
          } else {
            if (e.target.className == "active") {
              e.target.className = "active click";
            } else {
              e.target.className = "click"; //给当前点击td添加click
            }
          }
        });
        // 月份日历显示
        let year_tbody = document.querySelector(".date_year tbody");
        // 监听月份tbody的点击事件,当点击td时为当前点击的td添加 .click 类
        year_tbody.addEventListener("click", (e) => {
          let all_year_tds = year_tbody.querySelectorAll("td");
          let year = select_year.value;
          let month = select_month.value;
          all_year_tds.forEach((item) => {
            if (
              item.className == "active" ||
              item.className == "click active"
            ) {
              //.active 类 的td 则不清除 .activ 样式
              if (year == now_year && month == now_month) {
                item.className = "active";
              }
            }
            if (item.className == "click") {
              //清除之前添加的click
              item.className = "";
            }
          });
          if (e.target.className == "active") {
            e.target.className = "click active";
          } else {
            e.target.className = "click"; //给当前点击td添加click
          }
        });
        // 年份选择改变时
        select_year.onchange = function () {
          // 传入年 月 当月天数
          let year = this.value;
          let month = select_month.value;
          let date = getDates(year, month);
          showMonth(year, month, date);
          let all_year_tds = year_tbody.querySelectorAll("td");
          all_year_tds.forEach((item) => {
            if (item.className == "active") {
              if (year == now_year) {
                //判断当前年份月历是否为当前年，如果是则不清楚 .active 类
                item.className = "active";
              } else {
                item.className = "";
              }
            }
          });
        };
        // 月份选择改变时
        select_month.onchange = function () {
          // 传入年 月 当月天数
          let year = select_year.value;
          let month = this.value;
          let date = getDates(year, month);
          showMonth(year, month, date);
        };
        // 点击年按钮隐藏月份日历，显示年份月历 按钮添加 .btn_active 类
        //  点击月按钮隐藏年份月历，显示月份日历 按钮添加 .btn_active 类
        let year_btn = document.getElementById("btn_year");
        let month_btn = document.getElementById("btn_month");
        let year_date = document.querySelector(".date_year");
        let month_date = document.querySelector(".date_month");
        year_date.style.display = "none"; //默认隐藏年份月历
        year_btn.onclick = function () {
          this.className = "btn_active";
          month_btn.className = "";
          month_date.style.display = "none";
          year_date.style.display = "block";
          select_month.style.display = "none";
        };
        month_btn.onclick = function () {
          this.className = "btn_active";
          year_btn.className = "";
          year_date.style.display = "none";
          month_date.style.display = "block";
          select_month.style.display = "block";
        };
      };
    </script>
  </body>
</html>
